package com.core.indexer;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import com.core.indexer.IndexData.InvList;
import com.core.indexer.IndexData.Lexicon;

public class FileManager {

	private static FileManager mInstance = null;
	
	//Index
	BufferedWriter bwMap;
	BufferedWriter bwLexicon;
	FileOutputStream osInvlist;
	BufferedReader brStopList;
	
	//Search
	BufferedReader brMap;
	BufferedReader brLexicon;
	FileInputStream isInvList;
	
	private String InvListPaht;
	
	public static FileManager Get()
	{
		if(mInstance == null)
			mInstance = new FileManager();
		
		return mInstance;
	}
	
	public void InitForIndex() throws IOException
	{
		bwMap = new BufferedWriter(new FileWriter("Map"));
		bwLexicon = new BufferedWriter(new FileWriter("lexicon"));
		osInvlist = new FileOutputStream(new File("invlists"));
	}
	
	public void UnInitForIndex() throws IOException
	{
		bwMap.close();
		bwLexicon.close();
		osInvlist.close();
		brStopList.close();
	}
	
	public void InitForSearch(String strMap, String strLexicon, String strInvlists) throws FileNotFoundException
	{
		brMap = new BufferedReader(new FileReader(strMap));
		brLexicon = new BufferedReader(new FileReader(strLexicon));
		//isInvList = new FileInputStream(new File(strInvlists));
		InvListPaht = strInvlists;
	}
	
	public void UnInitForSearch() throws IOException
	{
		brMap.close();
		brLexicon.close();
		//isInvList.close();
	}
	
	public void saveMap(Document doc) throws IOException
	{
		if(bwMap == null)
			return;
		
		bwMap.write(String.format("%s,%f,%d", doc.GetDocNo(), doc.GetDocWight(), doc.GetDocSize()));
		bwMap.newLine();
	}
	
	public void loadMap(ArrayList<IndexData.DocList> docNoList, Map<String, Double> mapDocWeight) throws IOException
	{
		if(brMap == null)
			return;
		
		docNoList.clear();
		
		String line;
		while( (line = brMap.readLine()) != null)
		{
			String tempStr[] = line.split(",");
			docNoList.add(IndexData.Get().new DocList(tempStr[0], Double.valueOf(tempStr[1]), Integer.valueOf(tempStr[2])));
			mapDocWeight.put(tempStr[0], Double.valueOf(tempStr[1]));
		}
	}
	
	public void saveLexicon() throws IOException
	{
		for(Lexicon lexicon : IndexData.Get().getAllLexicon().values())
		{
			//Save in CSV format as [lexicon, count, pos, offset];
			bwLexicon.write(String.format("%s,%d,%d,%d", lexicon.GetKeyWord(), lexicon.GetCount(), lexicon.GetPosition(), lexicon.getInvertedListOffset()));
			bwLexicon.newLine();
		}
	}
	
	public void loadLexicon() throws IOException
	{
		if(brLexicon == null)
			return;
		
		String line;
		while((line = brLexicon.readLine()) != null)
		{
			String[] fields = line.split(",");
			String keyWord = fields[0];
			int count = Integer.valueOf(fields[1]);
			int pos = Integer.valueOf(fields[2]);
			int offset = Integer.valueOf(fields[3]);
			
			IndexData.Get().AddLexicon(keyWord, count, pos, offset);
		}
	}
	
	public void saveInvlists() throws IOException
	{
		//Test print result;
		for(InvList list : IndexData.Get().getInvList())
		{
			for(Integer key : list.mDocIDToLexiconCount.keySet())
			{
				ByteBuffer bb = ByteBuffer.allocate(4);
				bb.putInt(key);
				osInvlist.write(bb.array());
				
				bb.clear();
				bb.putInt(list.mDocIDToLexiconCount.get(key));
				osInvlist.write(bb.array());
			}
		}
	}
	
	
	public void loadInvlist(int nCount, int nOffset, Map<Integer, Integer> docList) throws IOException
	{	
		isInvList = new FileInputStream(InvListPaht);
		
		isInvList.skip(nOffset*8);
		byte[] intByte = new byte[nCount*8];
		if( isInvList.read(intByte, 0, nCount*8) > 0)
		{
			ByteBuffer bb = ByteBuffer.allocate(8);
			for( int i = 0; i < nCount;  i++)
			{
				bb.clear();
				bb.put(intByte, i*8, 8);
				docList.put(bb.getInt(0), bb.getInt(4));
			}
		}
		isInvList.close();
	}
	
	public Set<String> loadStoplist(String strStopListPath) throws IOException
	{
		if(strStopListPath.isEmpty())
			return null;
		
		brStopList = new BufferedReader(new FileReader(strStopListPath));
		if(brStopList == null)
			return null;
		Set<String> stopList = new HashSet<String>();
		String line;
		while((line = brStopList.readLine()) != null)
		{
			line.trim().toLowerCase();
			stopList.add(line);
		}
		return stopList;
	}
	
	private FileManager(){}
}
